﻿using System;
using System.Collections.Generic;
using DimensionsHelper.Common.Contracts.Metadata;
// ReSharper disable RedundantSuppressNullableWarningExpression

namespace DimensionsHelper.Services.Metadata;

public class Language : Context, ILanguage
{
    private static readonly LanguageInfo[] SupportedLanguages =
    [
        new() { LongCode = "af", ShortCode = "AF", Id = "" },
        new() { LongCode = "af-za", ShortCode = "AFK", Id = "" },
        new() { LongCode = "sq-al", ShortCode = "SQI", Id = "" },
        new() { LongCode = "ar", ShortCode = "AR", Id = "" },
        new() { LongCode = "ar-dz", ShortCode = "ARG", Id = "" },
        new() { LongCode = "ar-bh", ShortCode = "ARH", Id = "" },
        new() { LongCode = "ar-eg", ShortCode = "ARE", Id = "" },
        new() { LongCode = "ar-iq", ShortCode = "ARI", Id = "" },
        new() { LongCode = "ar-jo", ShortCode = "ARJ", Id = "" },
        new() { LongCode = "ar-kw", ShortCode = "ARK", Id = "" },
        new() { LongCode = "ar-lb", ShortCode = "ARB", Id = "" },
        new() { LongCode = "ar-ly", ShortCode = "ARL", Id = "" },
        new() { LongCode = "ar-ma", ShortCode = "ARM", Id = "" },
        new() { LongCode = "ar-om", ShortCode = "ARO", Id = "" },
        new() { LongCode = "ar-qa", ShortCode = "ARQ", Id = "" },
        new() { LongCode = "ar-sa", ShortCode = "ARA", Id = "" },
        new() { LongCode = "ar-sy", ShortCode = "ARS", Id = "" },
        new() { LongCode = "ar-tn", ShortCode = "ART", Id = "" },
        new() { LongCode = "ar-ae", ShortCode = "ARU", Id = "" },
        new() { LongCode = "ar-ye", ShortCode = "ARY", Id = "" },
        new() { LongCode = "az", ShortCode = "AZ", Id = "" },
        new() { LongCode = "hy-am", ShortCode = "HYE", Id = "" },
        new() { LongCode = "eu", ShortCode = "EU", Id = "" },
        new() { LongCode = "eu-es", ShortCode = "EUQ", Id = "" },
        new() { LongCode = "be", ShortCode = "BE", Id = "" },
        new() { LongCode = "be-by", ShortCode = "BEL", Id = "" },
        new() { LongCode = "bg", ShortCode = "BG", Id = "" },
        new() { LongCode = "bg-bg", ShortCode = "BGR", Id = "" },
        new() { LongCode = "ca", ShortCode = "CA", Id = "" },
        new() { LongCode = "ca-es", ShortCode = "CAT", Id = "" },
        new() { LongCode = "zh-cn", ShortCode = "CHS", Id = "1000" },
        new() { LongCode = "zh-hk", ShortCode = "ZHH", Id = "" },
        new() { LongCode = "zh-mo", ShortCode = "ZHM", Id = "" },
        new() { LongCode = "zh-sg", ShortCode = "ZHI", Id = "" },
        new() { LongCode = "zh-tw", ShortCode = "CHT", Id = "" },
        // new LanguageInfo { LongCode = "zh-chs"  , ShortCode = "CHS", Id = "" },
        // new LanguageInfo { LongCode = "zh-cht"  , ShortCode = "CHT", Id = "" },
        new() { LongCode = "hr-hr", ShortCode = "HRV", Id = "" },
        new() { LongCode = "cs", ShortCode = "CS", Id = "" },
        new() { LongCode = "cs-cz", ShortCode = "CSY", Id = "" },
        new() { LongCode = "da", ShortCode = "DA", Id = "" },
        new() { LongCode = "da-dk", ShortCode = "DAN", Id = "" },
        new() { LongCode = "nl-be", ShortCode = "NLB", Id = "" },
        new() { LongCode = "nl-nl", ShortCode = "NLD", Id = "" },
        new() { LongCode = "en", ShortCode = "EN", Id = "" },
        new() { LongCode = "en-au", ShortCode = "ENA", Id = "" },
        new() { LongCode = "en-bz", ShortCode = "ENL", Id = "" },
        new() { LongCode = "en-ca", ShortCode = "ENC", Id = "" },
        new() { LongCode = "en-cb", ShortCode = "ENB", Id = "" },
        new() { LongCode = "en-ie", ShortCode = "ENI", Id = "" },
        new() { LongCode = "en-jm", ShortCode = "ENJ", Id = "" },
        new() { LongCode = "en-nz", ShortCode = "ENZ", Id = "" },
        // new LanguageInfo { LongCode = "en-ph"   , ShortCode = "ENG", Id = "" },
        new() { LongCode = "en-za", ShortCode = "ENS", Id = "" },
        // new LanguageInfo { LongCode = "en-tt"   , ShortCode = "ENG", Id = "" },
        new() { LongCode = "en-gb", ShortCode = "ENG", Id = "0809" },
        new() { LongCode = "en-us", ShortCode = "ENU", Id = "" },
        new() { LongCode = "en-zw", ShortCode = "ENW", Id = "" },
        new() { LongCode = "eo", ShortCode = "EO", Id = "" },
        new() { LongCode = "et", ShortCode = "ET", Id = "" },
        new() { LongCode = "et-ee", ShortCode = "ETI", Id = "" },
        new() { LongCode = "fo", ShortCode = "FO", Id = "" },
        new() { LongCode = "fo-fe", ShortCode = "FOS", Id = "" },
        new() { LongCode = "fa", ShortCode = "FA", Id = "" },
        new() { LongCode = "fa-ir", ShortCode = "FAR", Id = "" },
        new() { LongCode = "fi", ShortCode = "FI", Id = "" },
        new() { LongCode = "fi-fi", ShortCode = "FIN", Id = "" },
        new() { LongCode = "fr", ShortCode = "FR", Id = "" },
        new() { LongCode = "fr-be", ShortCode = "FRB", Id = "" },
        new() { LongCode = "fr-ca", ShortCode = "FRC", Id = "" },
        // new LanguageInfo { LongCode = "fr-fr"   , ShortCode = "FRA", Id = "" },
        new() { LongCode = "fr-lu", ShortCode = "FRL", Id = "" },
        new() { LongCode = "fr-mc", ShortCode = "FRA", Id = "" },
        new() { LongCode = "fr-ch", ShortCode = "FRS", Id = "" },
        new() { LongCode = "de", ShortCode = "DE", Id = "" },
        new() { LongCode = "de-at", ShortCode = "DEA", Id = "" },
        new() { LongCode = "de-de", ShortCode = "DEU", Id = "0407" },
        new() { LongCode = "de-li", ShortCode = "DEC", Id = "" },
        new() { LongCode = "de-lu", ShortCode = "DEL", Id = "" },
        new() { LongCode = "de-ch", ShortCode = "DES", Id = "" },
        new() { LongCode = "el-gr", ShortCode = "ELL", Id = "" },
        new() { LongCode = "he-il", ShortCode = "HEB", Id = "" },
        new() { LongCode = "hi-in", ShortCode = "HIN", Id = "" },
        new() { LongCode = "hu-hu", ShortCode = "HUN", Id = "" },
        new() { LongCode = "is-is", ShortCode = "ISL", Id = "" },
        new() { LongCode = "id-id", ShortCode = "IND", Id = "" },
        new() { LongCode = "it-it", ShortCode = "ITA", Id = "" },
        new() { LongCode = "it-ch", ShortCode = "ITS", Id = "" },
        new() { LongCode = "ja-jp", ShortCode = "JPN", Id = "" },
        new() { LongCode = "kk-kz", ShortCode = "KKZ", Id = "" },
        new() { LongCode = "ko-kr", ShortCode = "KOR", Id = "" },
        new() { LongCode = "lv-lv", ShortCode = "LVI", Id = "" },
        new() { LongCode = "lt-lt", ShortCode = "LTH", Id = "" },
        new() { LongCode = "ms-my", ShortCode = "MSL", Id = "" },
        new() { LongCode = "nb-no", ShortCode = "NOR", Id = "" },
        new() { LongCode = "nn-no", ShortCode = "NON", Id = "" },
        new() { LongCode = "pl-pl", ShortCode = "PLK", Id = "" },
        new() { LongCode = "pt-br", ShortCode = "PTB", Id = "" },
        new() { LongCode = "pt-pt", ShortCode = "PTG", Id = "" },
        new() { LongCode = "ro-ro", ShortCode = "ROM", Id = "" },
        new() { LongCode = "ru-ru", ShortCode = "RUS", Id = "" },
        new() { LongCode = "sa-in", ShortCode = "SAN", Id = "" },
        new() { LongCode = "cy", ShortCode = "CY", Id = "" },
        new() { LongCode = "cy-sr-sp", ShortCode = "SRB", Id = "" },
        new() { LongCode = "lt-sr-sp", ShortCode = "SRL", Id = "" },
        new() { LongCode = "sk-sk", ShortCode = "SKY", Id = "" },
        new() { LongCode = "sl-si", ShortCode = "SLV", Id = "" },
        new() { LongCode = "es", ShortCode = "ES", Id = "" },
        // new LanguageInfo { LongCode = "es-ar"   , ShortCode = "ESS", Id = "" },
        new() { LongCode = "es-bo", ShortCode = "ESB", Id = "" },
        new() { LongCode = "es-cl", ShortCode = "ESL", Id = "" },
        new() { LongCode = "es-co", ShortCode = "ESO", Id = "" },
        new() { LongCode = "es-cr", ShortCode = "ESC", Id = "" },
        new() { LongCode = "es-do", ShortCode = "ESD", Id = "" },
        new() { LongCode = "es-ec", ShortCode = "ESF", Id = "" },
        new() { LongCode = "es-sv", ShortCode = "ESE", Id = "" },
        new() { LongCode = "es-gt", ShortCode = "ESG", Id = "" },
        new() { LongCode = "es-hn", ShortCode = "ESH", Id = "" },
        new() { LongCode = "es-mx", ShortCode = "ESM", Id = "" },
        new() { LongCode = "es-ni", ShortCode = "ESI", Id = "" },
        new() { LongCode = "es-pa", ShortCode = "ESA", Id = "" },
        new() { LongCode = "es-py", ShortCode = "ESZ", Id = "" },
        new() { LongCode = "es-pe", ShortCode = "ESR", Id = "" },
        new() { LongCode = "es-pr", ShortCode = "ESU", Id = "" },
        new() { LongCode = "es-es", ShortCode = "ESS", Id = "0C0A" },
        new() { LongCode = "es-uy", ShortCode = "ESY", Id = "" },
        new() { LongCode = "es-ve", ShortCode = "ESV", Id = "" },
        new() { LongCode = "sv-fi", ShortCode = "SVF", Id = "" },
        new() { LongCode = "sv-se", ShortCode = "SVE", Id = "" },
        new() { LongCode = "syr-sy", ShortCode = "SYR", Id = "" },
        new() { LongCode = "th-th", ShortCode = "THA", Id = "" },
        new() { LongCode = "tr-tr", ShortCode = "TRK", Id = "" },
        new() { LongCode = "uk-ua", ShortCode = "URK", Id = "" },
        new() { LongCode = "ur-pk", ShortCode = "URD", Id = "" },
        new() { LongCode = "vi-vn", ShortCode = "VIT", Id = "" },
        new() { LongCode = "dv", ShortCode = "DV", Id = "" },
        new() { LongCode = "dv-mv", ShortCode = "DIV", Id = "" },
        new() { LongCode = "el", ShortCode = "EL", Id = "" },
        new() { LongCode = "gl", ShortCode = "GL", Id = "" },
        new() { LongCode = "gl-es", ShortCode = "GLC", Id = "" },
        new() { LongCode = "gu", ShortCode = "GU", Id = "" },
        new() { LongCode = "gu-in", ShortCode = "GUJ", Id = "" }
    ];

    private static readonly Dictionary<string, LanguageInfo> LongCodeToLang;
    private static readonly Dictionary<string, LanguageInfo> ShortCodeToLang;

    static Language()
    {
        LongCodeToLang = new Dictionary<string, LanguageInfo>();
        ShortCodeToLang = new Dictionary<string, LanguageInfo>();

        foreach (var item in SupportedLanguages)
        {
            LongCodeToLang.Add(item.LongCode, item);
            ShortCodeToLang.Add(item.ShortCode, item);
        }
    }

    internal Language(IMetadataDocument document, ObjectType type, string name)
        : base(document, type, name)
    {
        Id = string.Empty;
        ShortName = string.Empty;
        LongName = string.Empty;
    }

    public string Id { get; internal set; }

    public string ShortName { get; internal set; }

    public string LongName { get; internal set; }

    /// <summary>
    ///     判断是否是受支持的语言长码号。
    /// </summary>
    /// <param name="longCode">语言长码号，中间有'-'分割</param>
    /// <returns></returns>
    public static bool IsSupportedLanguageLongCode(string longCode)
    {
        return LongCodeToLang.ContainsKey(longCode.ToLower());
    }

    /// <summary>
    ///     判断是否是受支持的语言短码号。
    /// </summary>
    /// <param name="shortCode">语言短码号，一般是2-3位英文字母</param>
    /// <returns></returns>
    public static bool IsSupportedLanguageShortCode(string shortCode)
    {
        return ShortCodeToLang.ContainsKey(shortCode.ToUpper());
    }

    /// <summary>
    ///     获取长语言码对应的短码
    /// </summary>
    /// <param name="longCode">长语言码，中间有'-'分隔</param>
    /// <returns>返回对应的短码，如果所给长码不受支持，返回 null。</returns>
    public static string? LongCodeToShortCode(string longCode)
    {
        return LongCodeToLang.TryGetValue(longCode.ToLower(), out var lang) ? lang.ShortCode : null;
    }

    /// <summary>
    ///     获取短语言码对应的长码
    /// </summary>
    /// <param name="shortCode">短语言码，一般是2-3位英文字母</param>
    /// <returns>返回对应的长码，如果所给短码不受支持，返回 null。</returns>
    public static string? ShortCodeToLongCode(string shortCode)
    {
        return ShortCodeToLang.TryGetValue(shortCode.ToUpper(), out var lang) ? lang.LongCode : null;
    }

    /// <summary>
    ///     初始化所有支持的语言到给定的MDM文档。
    /// </summary>
    /// <param name="document">给定的MDM文档</param>
    internal static void InitializeAllSupportedLanguages(IMetadataDocument document)
    {
        foreach (var item in SupportedLanguages)
        {
            var lang = (Language)document.Languages.GetByKey(item.LongCode);
            lang.LongName = item.LongCode;
            lang.ShortName = item.ShortCode;
            lang.Id = item.Id;
        }
    }

    private struct LanguageInfo
    {
        internal string LongCode;
        internal string ShortCode;
        internal string Id;
    }
}


public class Languages(IMetadataDocument document)
    : ContextsBase<ILanguage>(document, ObjectType.Languages), ILanguages
{
    public override ILanguage CreateObject(string name)
    {
        return new Language(Document, ObjectType.Language, name);
    }

    public ILanguage AddNew(string lang)
    {

        string? longCode = null;
        string? shortCode = null;

        if (Language.IsSupportedLanguageLongCode(lang))
        {
            longCode = lang;
            shortCode = Language.LongCodeToShortCode(lang);
        }
        else if (Language.IsSupportedLanguageShortCode(lang))
        {
            longCode = Language.ShortCodeToLongCode(lang);
            shortCode = lang;
        }

        if (string.IsNullOrEmpty(longCode) || string.IsNullOrEmpty(shortCode))
        {
            throw new Exception($"不支持的语言类型'{lang}'。");
        }

        if (TryGetByKey(longCode!, out var language))
        {
            return language;
        }

        language = new Language(Document, ObjectType.Language, longCode!.ToUpper())
        {
            ShortName = shortCode!,
            LongName = longCode
        };

        Add(language);

        return language;
    }

    protected override string KeySelector(ILanguage item)
    {
        return item.Name;
    }
}